package com.bocloud.cmp.service.app.resource;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.app.resource.Application;
import com.bocloud.cmp.entity.app.resource.ApplicationOpenshiftClusterInfo;
import com.bocloud.cmp.entity.app.resource.ApplicationSoftwareInfo;
import com.bocloud.cmp.entity.app.resource.DeployHistory;
import com.bocloud.cmp.entity.app.resource.OpenshiftCluster;
import com.bocloud.cmp.entity.app.resource.Registry;
import com.bocloud.cmp.entity.app.resource.RegistryImageInfo;
import com.bocloud.cmp.entity.app.resource.RegistrySoftware;
import com.bocloud.cmp.entity.app.resource.Software;
import com.bocloud.cmp.enums.app.ApplicationEnum;
import com.bocloud.cmp.enums.app.CommonEnum.Property;
import com.bocloud.cmp.enums.app.CommonEnum.Status;
import com.bocloud.cmp.enums.app.DeployHistoryEnum;
import com.bocloud.cmp.enums.app.SoftwareEnum.Type;
import com.bocloud.cmp.interfaces.app.resource.SoftwareService;
import com.bocloud.cmp.service.model.OperateResult;
import com.bocloud.cmp.service.utils.DockerImageInfo;
import com.bocloud.cmp.service.utils.FileUtil;
import com.bocloud.cmp.service.utils.ImageUtil;
import com.bocloud.cmp.service.utils.OpenshiftUtil;
import com.bocloud.cmp.service.utils.RegistryUtil;
import com.bocloud.common.http.ExtendHttpClient;
import com.bocloud.common.http.HttpClient;
import com.bocloud.common.model.BsmResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.RequestUser;
import com.bocloud.common.model.Result;
import com.bocloud.common.model.SimpleBean;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.ListTool;
import com.bocloud.soc.entity.Authority;
import com.bocloud.soc.entity.Department;
import com.bocloud.soc.entity.Role;
import com.bocloud.soc.entity.User;
import com.google.common.collect.Maps;

import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.ContainerPort;
import io.fabric8.kubernetes.api.model.EnvVar;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.api.model.PodSpec;
import io.fabric8.kubernetes.api.model.PodTemplateSpec;
import io.fabric8.kubernetes.api.model.ReplicationController;
import io.fabric8.kubernetes.api.model.ReplicationControllerSpec;
import io.fabric8.kubernetes.api.model.ServicePort;
import io.fabric8.kubernetes.api.model.ServiceSpec;

/**
 * @author zjm
 * @date 2017年3月17日
 */
@Service("softwareService")
public class SoftwareServiceImpl extends CommonServiceImpl implements SoftwareService {

	private static Logger logger = LoggerFactory.getLogger(SoftwareServiceImpl.class);

	@Override
	public BsmResult list(int page, int rows, List<Param> params, Map<String, String> sorter, Boolean simple,
			RequestUser requestUser) {
		GridBean gridBean;
		BsmResult bsmResult = new BsmResult();
		if (ListTool.isEmpty(params)) {
			params = new ArrayList<Param>();
		}
		if (null == sorter) {
			sorter = Maps.newHashMap();
		}
		sorter.put("gmtCreate", Common.ONE);
		try {
			String deptId = userService.listDept(requestUser.getId());
			// 判断当前用户是否拥有查看“容器平台”的权限，如果有则可以查看所有的镜像
			User user = null;
			if (null == (user = queryUser(requestUser.getId(), bsmResult))) {
				return bsmResult;
			}
			List<Role> roles = roleDao.listByUid(user.getId());
			for (Role role : roles) {
				List<Authority> authorities = authDao.listByRid(role.getId());
				for (Authority authority : authorities) {
					// TODO 和威哥少龙沟通后暂时写死判断“容器平台”权限的id
					if (authority.getId().equals(new Long(132))) {
						deptId = null;
						break;
					}
				}
			}
			int total = softwareDao.count(params, deptId);
			if (simple) {
				List<SimpleBean> beans = softwareDao.list(params, sorter, deptId);
				gridBean = new GridBean(1, 1, total, beans);
			} else {
				List<Software> list = softwareDao.list(page, rows, params, sorter, deptId);
				gridBean = GridHelper.getBean(page, rows, total, list);
			}
			bsmResult.setSuccess(true);
			bsmResult.setData(gridBean);
			bsmResult.setMessage("镜像查询成功！");
		} catch (Exception e) {
			logger.error("list software failure:", e);
			bsmResult.setMessage("镜像查询失败！");
		} finally {
			saveLog("software/operation", "镜像列表查询", bsmResult.getMessage(), requestUser.getId());
		}
		return bsmResult;
	}

	@Override
	public BsmResult create(RequestUser requestUser, Software software) {
		software.setCreaterId(requestUser.getId());
		software.setGmtCreate(new Date());
		software.setMenderId(requestUser.getId());
		software.setGmtModify(new Date());
		BsmResult result = new BsmResult();
		try {
			User user = null;
			if (null == (user = queryUser(requestUser.getId(), result))) {
				return result;
			}
			software.setDeptId(user.getDepartId());
			softwareDao.save(software);
			result.setSuccess(true);
			result.setMessage("创建镜像成功！");
		} catch (Exception e) {
			logger.error("create software exception:", e);
			result.setMessage("创建镜像失败！");
		} finally {
			saveLog("software/operation", "创建镜像", result.getMessage(), requestUser.getId());
		}
		return result;
	}

	@Override
	public BsmResult detail(Long id, RequestUser user) {
		BsmResult result = new BsmResult(false, "");
		try {
			Software software = softwareDao.query(id);
			if (null == software) {
				result.setMessage("仓库不存在");
			} else {
				result.setSuccess(true);
				result.setData(software);
				result.setMessage("获取镜像表详情成功");
			}
		} catch (Exception e) {
			logger.error("query software error：", e);
			result.setMessage("获取镜像表详情失败");
		}
		saveLog("software/operation", "镜像表详情", result.getMessage(), user.getId());
		return result;
	}

	@Override
	public BsmResult remove(List<Long> ids, Long userId) {
		BsmResult bsmResult = new BsmResult();
		HttpClient client = new HttpClient();
		ExtendHttpClient extendHttpClient = new ExtendHttpClient();
		try {
			for (Long id : ids) {
				Software software;
				if ((software = querySoftware(id, bsmResult)) == null) {
					return bsmResult;
				}
				RegistryImageInfo registryImageInfo;
				if (null == (registryImageInfo = queryRegistryImageInfo(id, bsmResult))) {
					return bsmResult;
				}
				Registry registry;
				if ((registry = queryRegistry(registryImageInfo.getRepositoryId(), bsmResult)) == null) {
					return bsmResult;
				}
				if (registry.getStatus().equals(String.valueOf(Status.LOCK.ordinal()))) {
					return new BsmResult(false, "仓库锁定中不允许操作！");
				}
				String imagesName = software.getName();
				if (StringUtils.isNotBlank(registryImageInfo.getNamespace())) {
					imagesName = registryImageInfo.getNamespace() + "/" + imagesName;
				}
				bsmResult = RegistryUtil.getSoftwareDigestByNameAndVersion(registry.getAddress(),
						registry.getRegistryPort(), imagesName, software.getVersion(), extendHttpClient);
				if (bsmResult.isSuccess()) {
					String digest = "sha256:" + bsmResult.getData().toString();
					if (!(bsmResult = RegistryUtil.deleteSoftwareByNameAndDigest(registry.getAddress(),
							registry.getRegistryPort(), imagesName, digest, client)).isSuccess()) {
						return bsmResult;
					}
				}
				if (!removeSoftware(id, bsmResult)) {
					return bsmResult;
				}
			}
			logger.info("镜像删除成功！");
			bsmResult.setSuccess(true);
			bsmResult.setMessage("镜像删除成功！");
		} catch (Exception e) {
			logger.error("镜像删除失败 ！", e);
			bsmResult.setMessage("镜像删除失败 ！");
		} finally {
			saveLog("software/operation", "删除镜像", bsmResult.getMessage(), userId);
		}
		return bsmResult;
	}

	@Override
	public BsmResult modify(Software software, Long userId) {
		software.setMenderId(userId);
		software.setGmtModify(new Date());
		BsmResult result = new BsmResult();
		try {
			if (softwareDao.update(software)) {
				result.setSuccess(true);
				result.setMessage("修改镜像信息成功！");
			} else {
				result.setMessage("修改镜像信息失败！");
			}
		} catch (Exception e) {
			logger.error("modify software fail:", e);
			result.setMessage("修改镜像信息失败！");
		} finally {
			saveLog("software/operation", "镜像信息修改", result.getMessage(), userId);
		}
		return result;
	}

	@Override
	public BsmResult imports(RequestUser requestUser, Long registryId, String filePath) {
		BsmResult result = new BsmResult();
		File imageFile = new File(filePath);
		String fileName = imageFile.getName();
		if (!fileName.substring(fileName.lastIndexOf(".") + 1).equals("tar")) {
			logger.warn("不支持上传的文件格式！目前只支持tar类型的镜像包");
			result.setMessage("不支持上传的文件格式！目前只支持tar类型的镜像包");
			FileUtil.deleteDirectory(imageFile);
			saveLog("software/operation", "镜像导入", result.getMessage(), requestUser.getId());
			return result;
		}
		// 获取仓库信息
		Registry registry;
		if ((registry = queryRegistry(registryId, result)) == null) {
			FileUtil.deleteDirectory(imageFile);
			saveLog("software/operation", "镜像导入", result.getMessage(), requestUser.getId());
			return result;
		}
		if (registry.getStatus().equals(String.valueOf(Status.LOCK.ordinal()))) {
			result.setMessage("仓库锁定中不允许操作！");
			result.setSuccess(false);
			saveLog("software/operation", "镜像导入", result.getMessage(), requestUser.getId());
			return result;
		}
		String registryIp = registry.getAddress();
		int registryPort = registry.getRegistryPort();

		User user = null;
		if (null == (user = queryUser(requestUser.getId(), result))) {
			FileUtil.deleteDirectory(imageFile);
			logger.error(result.getMessage());
			saveLog("software/operation", "镜像导入", result.getMessage(), requestUser.getId());
			return result;
		}
		Department department = null;
		if (null != user.getDepartId()) {
			try {
				department = departmentDao.query(user.getDepartId());
			} catch (Exception e) {
				result.setMessage("获取用户组织部门信息失败！");
				logger.error(result.getMessage(), e);
				saveLog("software/operation", "镜像导入", result.getMessage(), requestUser.getId());
				return result;
			}
		}
		if (null == department || null == user.getDepartId()) {
			result.setMessage("获取用户组织部门信息失败！");
			logger.error(result.getMessage());
			saveLog("software/operation", "镜像导入", result.getMessage(), requestUser.getId());
			return result;
		}

		Long departmentId = department.getId();
		// 获取用户的组织机构名称，作为导入镜像的namespace
		String namespace = department.getName();
		try {
			// 启动一个线程从MQ上获取数据
			new Thread(new Runnable() {
				@Override
				public void run() {
					BsmResult bsmResult = new BsmResult();
					Result result = ImageUtil.loadByAPI(imageFile, registryIp);
					if (!result.isSuccess() || StringUtils.isBlank(result.getMessage())) {
						FileUtil.deleteDirectory(imageFile);
						result.setMessage("加载镜像信息失败：" + result.getMessage());
						logger.error(result.getMessage());
						saveLog("software/operation", "镜像导入", result.getMessage(), requestUser.getId());
						resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(),
								"software/importImage", requestUser.getId()));
						return;
					}
					String[] loadImages = result.getMessage().replace("Loaded image: ", "").split("\n");
					HttpClient client = new HttpClient();
					ExtendHttpClient extendHttpClient = new ExtendHttpClient();
					// 如果导入的镜像是已经按照格式打完了tag，需要重新打一个当前用户的组织机构名称作为命名空间的tag
					for (String loadImage : loadImages) {
						String imageName = loadImage;
						if (imageName.indexOf("/") > 0) {
							if (imageName.substring(0, imageName.indexOf("/")).contains(":5000")) {
								imageName = (imageName.substring(imageName.indexOf("/") + 1))
										.substring((imageName.substring(imageName.indexOf("/") + 1).indexOf("/") + 1));
							} else {
								imageName = imageName.substring(imageName.indexOf("/") + 1);
							}
						}
						// 获取新的镜像名称
						@SuppressWarnings("all")
						String imageNewName = "localhost:" + registryPort + "/" + namespace + "/" + imageName;
						String imageOldName = imageName.substring(0, imageName.indexOf(":"));
						String imageOldTag = imageName.substring(imageName.indexOf(":") + 1);
						// 判断仓库是否包含该镜像
						bsmResult = RegistryUtil.getSoftwareDetailByNameAndVersion(registryIp, registryPort,
								namespace + "/" + imageOldName, imageOldTag, client);
						if (null != bsmResult.getData()) {
							bsmResult.setMessage("仓库中已经包含[" + namespace + "/" + imageOldName + "]镜像！");
							FileUtil.deleteDirectory(imageFile);
							logger.warn(bsmResult.getMessage());
							saveLog("software/operation", "镜像导入", bsmResult.getMessage(), requestUser.getId());
							resourceEventPublisher.send(new OperateResult(bsmResult.isSuccess(), bsmResult.getMessage(),
									"software/importImage", bsmResult.getData(), requestUser.getId()));
							continue;
						}
						if (!ImageUtil.tag(loadImage, imageNewName, registryIp)) {
							FileUtil.deleteDirectory(imageFile);
							bsmResult.setMessage("镜像[" + imageName + "]打标[" + imageNewName + "]失败");
							logger.error(bsmResult.getMessage());
							saveLog("software/operation", "镜像导入", bsmResult.getMessage(), requestUser.getId());
							resourceEventPublisher.send(new OperateResult(bsmResult.isSuccess(), bsmResult.getMessage(),
									"software/importImage", requestUser.getId()));
							continue;
						}
						if (!ImageUtil.push(imageNewName, registryIp)) {
							FileUtil.deleteDirectory(imageFile);
							bsmResult.setMessage("推送[" + imageNewName + "]镜像失败");
							logger.error(bsmResult.getMessage());
							saveLog("software/operation", "镜像导入", bsmResult.getMessage(), requestUser.getId());
							resourceEventPublisher.send(new OperateResult(bsmResult.isSuccess(), bsmResult.getMessage(),
									"software/importImage", requestUser.getId()));
							continue;
						}
						Software software = new Software();
						// 重新获取镜像信息
						bsmResult = RegistryUtil.getSoftwareDigestByNameAndVersion(registryIp, registryPort,
								namespace + "/" + imageOldName, imageOldTag, extendHttpClient);
						if (!bsmResult.isSuccess()) {
							bsmResult.setMessage(
									"获取镜像[" + namespace + "/" + imageOldName + ":" + imageOldTag + "]digest信息失败！");
							FileUtil.deleteDirectory(imageFile);
							logger.error(bsmResult.getMessage());
							saveLog("software/operation", "镜像导入", bsmResult.getMessage(), requestUser.getId());
							resourceEventPublisher.send(new OperateResult(bsmResult.isSuccess(), bsmResult.getMessage(),
									"software/importImage", requestUser.getId()));
							continue;
						}
						software.setDeptId(departmentId);
						software.setUuid(bsmResult.getData().toString());
						software.setName(imageOldName);
						software.setVersion(imageOldTag);
						// TODO 暂时都是公有镜像
						software.setProperty(Property.PUBLIC.ordinal());
						software.setType(Type.CONTAINER.ordinal());
						software.setStatus(Integer.toString(Status.NORMAL.ordinal()));
						software.setUsage_count(0);
						software.setDeleted(false);
						software.setGmtCreate(new Date());
						software.setMenderId(requestUser.getId());
						software.setGmtModify(new Date());
						software.setCreaterId(requestUser.getId());
						try {
							softwareDao.save(software);
						} catch (Exception e) {
							bsmResult.setMessage("保存镜像[" + imageNewName + "]失败！");
							FileUtil.deleteDirectory(imageFile);
							logger.error(bsmResult.getMessage(), e);
							saveLog("software/operation", "镜像导入", bsmResult.getMessage(), requestUser.getId());
							resourceEventPublisher.send(new OperateResult(bsmResult.isSuccess(), bsmResult.getMessage(),
									"software/importImage", requestUser.getId()));
							continue;
						}
						RegistrySoftware registrySoftware = new RegistrySoftware();
						registrySoftware.setNamespace(namespace);
						registrySoftware.setRepositoryId(registryId);
						registrySoftware.setSoftwareId(software.getId());
						try {
							registrySoftwareDao.saveRegistrySoftware(registrySoftware);
						} catch (Exception e) {
							bsmResult.setMessage("保存仓库镜像[" + imageNewName + "]信息失败！");
							logger.error(bsmResult.getMessage(), e);
							FileUtil.deleteDirectory(imageFile);
							saveLog("software/operation", "镜像导入", bsmResult.getMessage(), requestUser.getId());
							resourceEventPublisher.send(new OperateResult(bsmResult.isSuccess(), bsmResult.getMessage(),
									"software/importImage", requestUser.getId()));
							continue;
						}
						bsmResult.setMessage("导入镜像[" + imageNewName + "]成功！");
						logger.info(bsmResult.getMessage());
						FileUtil.deleteDirectory(imageFile);
						saveLog("software/operation", "镜像导入", bsmResult.getMessage(), requestUser.getId());
						resourceEventPublisher.send(new OperateResult(bsmResult.isSuccess(), bsmResult.getMessage(),
								"software/importImage", bsmResult.getData(), requestUser.getId()));
						continue;
					}
					return;
				}
			}).start();
			return new BsmResult(true, "镜像导入任务已经下发，正在执行……");
		} catch (Exception e) {
			logger.error("image import failure:", e);
			result.setSuccess(false);
			result.setMessage("镜像导入失败!");
			saveLog("software/operation", "镜像导入", result.getMessage(), requestUser.getId());
			return result;
		}
	}

	@Override
	public BsmResult inspect(Long softwareId, RequestUser user) {
		BsmResult bsmResult = new BsmResult();
		try {
			bsmResult.setSuccess(false);
			Software software;
			if ((software = querySoftware(softwareId, bsmResult)) == null) {
				return bsmResult;
			}
			// 获取仓库镜像中间表信息
			RegistryImageInfo registryImageInfo;
			if (null == (registryImageInfo = queryRegistryImageInfo(softwareId, bsmResult))) {
				return bsmResult;
			}
			// 获取仓库信息
			Registry registry;
			if ((registry = queryRegistry(registryImageInfo.getRepositoryId(), bsmResult)) == null) {
				return bsmResult;
			}
			if (StringUtils.isNotBlank(registryImageInfo.getNamespace())) {
				bsmResult = RegistryUtil.getSoftwareDetailByNameAndVersion(registry.getAddress(),
						registry.getRegistryPort(), registryImageInfo.getNamespace() + "/" + software.getName(),
						software.getVersion(), new HttpClient());
			} else {
				bsmResult = RegistryUtil.getSoftwareDetailByNameAndVersion(registry.getAddress(),
						registry.getRegistryPort(), software.getName(), software.getVersion(), new HttpClient());
			}
			if (!bsmResult.isSuccess()) {
				return bsmResult;
			}

			// 构造dockerimage的实体类
			DockerImageInfo dockerImageInfo = new DockerImageInfo();
			JSONObject softwareObject = JSONObject.parseObject(bsmResult.getData().toString());
			JSONArray env = JSONObject
					.parseObject(
							softwareObject.getJSONArray("history").getJSONObject(0).get("v1Compatibility").toString())
					.getJSONObject("config").getJSONArray("Env");
			if (null != env) {
				dockerImageInfo.setEnv(env.toJSONString());
			}
			JSONObject exposedPorts = JSONObject
					.parseObject(
							softwareObject.getJSONArray("history").getJSONObject(0).get("v1Compatibility").toString())
					.getJSONObject("config").getJSONObject("ExposedPorts");
			if (null != exposedPorts) {
				dockerImageInfo.setExposedPort(exposedPorts.toJSONString());
			}
			BeanUtils.copyProperties(software, dockerImageInfo);
			// TODO 需要获取镜像层
			bsmResult.setData(dockerImageInfo);
			bsmResult.setSuccess(true);
		} catch (BeansException e) {
			bsmResult.setSuccess(false);
			bsmResult.setMessage("获取镜像信息失败！");
		} finally {
			saveLog("software/operation", "服务端镜像详情信息", bsmResult.getMessage(), user.getId());
		}
		return bsmResult;
	}

	@Override
	public BsmResult remove(Long registryId, Long softwareId) {
		BsmResult bsmResult = new BsmResult();
		bsmResult.setSuccess(false);
		Software software;
		if ((software = querySoftware(softwareId, bsmResult)) == null) {
			return bsmResult;
		}
		// 获取仓库信息
		Registry registry;
		if ((registry = queryRegistry(registryId, bsmResult)) == null) {
			return bsmResult;
		}
		if (registry.getStatus().equals(String.valueOf(Status.LOCK.ordinal()))) {
			return new BsmResult(false, "仓库锁定中不允许操作！");
		}
		String registryIp = registry.getAddress();
		if (ImageUtil.remove(software.getName(), registryIp) && !removeSoftware(softwareId, bsmResult)) {
			return bsmResult;
		}
		bsmResult.setSuccess(true);
		bsmResult.setMessage("镜像删除成功！");
		return bsmResult;
	}

	@Override
	public BsmResult count(RequestUser requestUser) {
		BsmResult bsmResult = new BsmResult();
		int count;
		try {
			String deptId = userService.listDept(requestUser.getId());
			// 判断当前用户是否拥有查看“容器平台”的权限，如果有则可以查看所有的镜像
			User user = null;
			if (null == (user = queryUser(requestUser.getId(), bsmResult))) {
				return bsmResult;
			}
			List<Role> roles = roleDao.listByUid(user.getId());
			for (Role role : roles) {
				List<Authority> authorities = authDao.listByRid(role.getId());
				for (Authority authority : authorities) {
					if (authority.getId().equals(new Long(132))) {
						deptId = null;
						break;
					}
				}
			}
			count = softwareDao.count(new ArrayList<>(), deptId);
			bsmResult.setSuccess(true);
			bsmResult.setData(count);
			bsmResult.setMessage("镜像总数为：" + count);
		} catch (Exception e) {
			logger.error("统计镜像失败！", e);
			bsmResult.setSuccess(false);
			bsmResult.setMessage("统计镜像失败！");
			return bsmResult;
		} finally {
			saveLog("software/operation", "镜像数据统计", bsmResult.getMessage(), requestUser.getId());
		}
		return bsmResult;
	}

	@Override
	public BsmResult deploy(Long appId, Long softwareId, Long clusterId, Map<String, String> labels,
			Map<String, String> envs, RequestUser user) {
		BsmResult bsmResult = new BsmResult();
		bsmResult.setSuccess(false);
		Software software;
		if (null == (software = querySoftware(softwareId, bsmResult))) {
			saveLog("software/operation", "镜像部署", bsmResult.getMessage(), user.getId());
			return bsmResult;
		}
		Application application;
		if (null == (application = queryApplication(appId, bsmResult))) {
			saveLog("software/operation", "镜像部署", bsmResult.getMessage(), user.getId());
			return bsmResult;
		}
		application.setStatus(ApplicationEnum.Status.EXECUTE_DEPLOY.toString());
		modifyApplication(application, bsmResult);
		OpenshiftCluster openshiftCluster;
		if (null == (openshiftCluster = queryOpenshiftCluster(clusterId, bsmResult))) {
			saveLog("software/operation", "镜像部署", bsmResult.getMessage(), user.getId());
			return bsmResult;
		}
		// 设置应用名字追加日期和随机字符串
		String appName = application.getName() + "-" + RandomStringUtils.randomAlphanumeric(7).toLowerCase();
		// 对所有k8s的资源组件追加一个label，并固定label的key值，value值是应用名，便于按照应用查找组件
		labels.put(OpenshiftUtil.UNIFIED_LABEL_KEY, application.getName());
		// 对所有k8s的资源组件追加一个label，并固定label的key值，value值是应用名-日期和随机数，防止资源label完全相同
		labels.put(OpenshiftUtil.DIFF_LABEL_KEY, appName);
		// 设置资源名称（应用名字-日期和随机数）
		String rcName = appName;
		String serviceName = appName;
		// 获取仓库镜像中间表信息
		RegistryImageInfo registryImageInfo;
		if (null == (registryImageInfo = queryRegistryImageInfo(softwareId, bsmResult))) {
			saveLog("software/operation", "镜像部署", bsmResult.getMessage(), user.getId());
			return bsmResult;
		}
		// 获取仓库信息
		Registry registry;
		if (null == (registry = queryRegistry(registryImageInfo.getRepositoryId(), bsmResult))) {
			saveLog("software/operation", "镜像部署", bsmResult.getMessage(), user.getId());
			return bsmResult;
		}
		if (registry.getStatus().equals(String.valueOf(Status.LOCK.ordinal()))) {
			saveLog("software/operation", "镜像部署", bsmResult.getMessage(), user.getId());
			return new BsmResult(false, "仓库锁定中不允许操作！");
		}
		// 设置镜像名称加版本号
		String imageName;
		// 追加不重复label，防止资源label完全相同
		labels.put("app_name", appName);
		// 获取镜像端口号
		if (StringUtils.isNoneBlank(registryImageInfo.getNamespace())) {
			imageName = registryImageInfo.getNamespace() + "/" + software.getName() + ":" + software.getVersion();
			bsmResult = RegistryUtil.getSoftwareDetailByNameAndVersion(registry.getAddress(),
					registry.getRegistryPort(), registryImageInfo.getNamespace() + "/" + software.getName(),
					software.getVersion(), new HttpClient());
		} else {
			imageName = software.getName() + ":" + software.getVersion();
			bsmResult = RegistryUtil.getSoftwareDetailByNameAndVersion(registry.getAddress(),
					registry.getRegistryPort(), software.getName(), software.getVersion(), new HttpClient());
		}
		if (!bsmResult.isSuccess()) {
			saveLog("software/operation", "镜像部署", bsmResult.getMessage(), user.getId());
			return bsmResult;
		}
		List<Integer> ports = new ArrayList<>();
		JSONObject softwareObject = JSONObject.parseObject(bsmResult.getData().toString());
		JSONObject exposedPorts = JSONObject
				.parseObject(softwareObject.getJSONArray("history").getJSONObject(0).get("v1Compatibility").toString())
				.getJSONObject("config").getJSONObject("ExposedPorts");
		if (null != exposedPorts) {
			String[] exposedPortsArray = exposedPorts.toJSONString().split(",");
			for (String exposedPort : exposedPortsArray) {
				String port = exposedPort.substring(exposedPort.indexOf("\"") + 1, exposedPort.indexOf("/"));
				if (StringUtils.isNotBlank(port)) {
					ports.add(Integer.parseInt(port));
				}
			}
		}
		try {
			// 启动一个线程从MQ上获取数据
			new Thread(new Runnable() {
				@Override
				public void run() {
					// 构造Rc
					ReplicationController rc = constructRc(rcName, imageName, labels, envs, ports);
					// 构造service
					io.fabric8.kubernetes.api.model.Service service = constructService(serviceName, labels, envs,
							ports);
					BsmResult bsmResult = oseUtil.createReplicationController(openshiftCluster.getProxyUrl(), rc);
					if (bsmResult.isSuccess()) {
						rc = (ReplicationController) bsmResult.getData();
						bsmResult = oseUtil.createService(openshiftCluster.getProxyUrl(), service);
						if (!bsmResult.isSuccess()) {
							logger.error(bsmResult.getMessage());
							List<ReplicationController> rcs = new ArrayList<>();
							rcs.add(rc);
							oseUtil.deleteReplicationControllers(openshiftCluster.getProxyUrl(), rcs);
							saveLog("software/operation", "镜像部署", bsmResult.getMessage(), user.getId());
							resourceEventPublisher.send(new OperateResult(bsmResult.isSuccess(), bsmResult.getMessage(),
									"application/imageDeploy"));
							return;
						}
						service = (io.fabric8.kubernetes.api.model.Service) bsmResult.getData();
					} else {
						logger.error(bsmResult.getMessage());
					}
					DeployHistory deployHistory = new DeployHistory();
					deployHistory.setStatus(DeployHistoryEnum.Status.FAIL.toString());
					// 如果部署成功添加镜像中间表并修改应用信息
					if (bsmResult.isSuccess()) {
						if ((bsmResult = insertSoftwareMiddleTable(softwareId, application, clusterId,
								rc.getMetadata().getName())).isSuccess()) {
							deployHistory.setStatus(DeployHistoryEnum.Status.SUCCESS.toString());
							bsmResult.setMessage("镜像部署成功！");
						} else {
							bsmResult.setMessage("镜像部署失败！" + bsmResult.getMessage());
						}
					} else {
						bsmResult.setMessage("镜像部署失败！" + bsmResult.getMessage());
					}

					// 添加部署历史记录
					deployHistory.setAppId(appId);
					deployHistory.setName(rcName);
					deployHistory.setResourceType("ReplicationController");
					deployHistory.setResourceName(rcName);
					deployHistory.setCurrentVersion(imageName);
					deployHistory.setDeleted(false);
					deployHistory.setGmtCreate(new Date());
					deployHistory.setGmtModify(new Date());
					deployHistory.setCreaterId(user.getId());
					deployHistory.setMenderId(user.getId());
					deployHistory.setOwnerId(user.getId());
					deployHistory.setTenantId(user.getTenantId());
					deployHistory.setRemark(bsmResult.getMessage());
					if (!saveDeployHistroy(deployHistory, bsmResult)) {
						saveLog("software/operation", "镜像部署", bsmResult.getMessage(), user.getId());
						resourceEventPublisher
								.send(new OperateResult(false, "镜像部署成功！添加部署历史失败！", "application/imageDeploy"));
						return;
					}
					saveLog("software/operation", "镜像部署", bsmResult.getMessage(), user.getId());
					resourceEventPublisher.send(new OperateResult(bsmResult.isSuccess(), bsmResult.getMessage(),
							"application/imageDeploy"));
					return;
				}
			}).start();
			return new BsmResult(true, "镜像部署任务已经下发，正在执行……");
		} catch (Exception e) {
			logger.error("image deploy failure:", e);
			bsmResult.setSuccess(false);
			bsmResult.setMessage("镜像部署失败!");
			saveLog("software/operation", "镜像部署", bsmResult.getMessage(), user.getId());
			return bsmResult;
		}
	}

	private boolean modifyApplication(Application application, BsmResult bsmResult) {
		boolean result = false;
		try {
			result = applicationDao.update(application);
		} catch (Exception e) {
			logger.error("更新应用数据失败！", e);
			bsmResult.setMessage("更新应用数据失败！");
		}
		if (!result) {
			bsmResult.setMessage("更新应用数据失败！");
		}
		return result;
	}

	private boolean saveApplicationSoftwareInfo(ApplicationSoftwareInfo applicationSoftwareInfo, BsmResult bsmResult) {
		boolean result = false;
		try {
			result = applicationSoftwareInfoDao.saveApplicationSoftwareInfo(applicationSoftwareInfo);
		} catch (Exception e) {
			logger.error("添加应用镜像关联数据失败！", e);
			bsmResult.setMessage("添加应用镜像关联数据失败！");
		}
		if (!result) {
			bsmResult.setMessage("添加应用镜像关联数据失败！");
		}
		return result;
	}

	private boolean saveApplicationOpenshiftClusterInfo(ApplicationOpenshiftClusterInfo applicationOpenshiftClusterInfo,
			BsmResult bsmResult) {
		boolean result = false;
		try {
			result = applicationOpenshiftClusterInfoDao
					.saveApplicationOpenshiftClusterInfo(applicationOpenshiftClusterInfo);
		} catch (Exception e) {
			logger.error("添加应用集群关联数据失败！", e);
			bsmResult.setMessage("添加应用集群关联数据失败！");
		}
		if (!result) {
			bsmResult.setMessage("添加应用集群关联数据失败！");
		}
		return result;
	}

	private boolean saveDeployHistroy(DeployHistory deployHistory, BsmResult bsmResult) {
		boolean result = false;
		try {
			result = deployHistoryDao.baseSave(deployHistory);
		} catch (Exception e) {
			logger.error("镜像部署成功！添加部署历史失败！", e);
			bsmResult.setMessage("镜像部署成功！添加部署历史失败！");
		}
		if (!result) {
			bsmResult.setMessage("镜像部署成功！添加部署历史失败！");
		}
		bsmResult.setSuccess(result);
		return result;
	}

	@Transactional
	private boolean removeSoftware(Long id, BsmResult bsmResult) {
		boolean result = false;
		try {
			result = softwareDao.remove(Software.class, id) && softwareDao.deleteRegistrySoftwareInfo(id)
					&& softwareDao.deleteSoftwareAppInfo(id);
		} catch (Exception e) {
			logger.error("服务器端镜像删除成功，数据库镜像删除失败！", e);
			bsmResult.setMessage("服务器端镜像删除成功，数据库镜像删除失败！");
		}
		if (!result) {
			bsmResult.setMessage("服务器端镜像删除成功，数据库镜像删除失败！");
		}
		return result;
	}

	// TODO 暂不支持Deployment资源的管理，请不要删除
	// @SuppressWarnings("all")
	// private Deployment constructDeployment(String deploymentName, String
	// image, Map<String, String> labels,
	// Map<String, String> envs) {
	// ObjectMeta objectMeta = new ObjectMeta();
	// objectMeta.setName(deploymentName);
	// objectMeta.setNamespace(OpenshiftUtil.DEFAULT_NAMESPACE);
	//
	// DeploymentSpec deploymentSpec = new DeploymentSpec();
	// // 默认实例数启动一个
	// deploymentSpec.setReplicas(1);
	// PodTemplateSpec podTemplateSpec = new PodTemplateSpec();
	// ObjectMeta podObjectMeta = new ObjectMeta();
	// podObjectMeta.setLabels(labels);
	// podTemplateSpec.setMetadata(podObjectMeta);
	// PodSpec podSpec = new PodSpec();
	// List<Container> containers = new ArrayList<>();
	// Container container = new Container();
	// container.setName(deploymentName);
	// container.setImage(image);
	// List<ContainerPort> containerPorts = new ArrayList<>();
	//
	// ContainerPort containerPort = new ContainerPort();
	// // 暂时写死，获取导入镜像的端口信息
	// containerPort.setContainerPort(8080);
	// containerPorts.add(containerPort);
	// container.setPorts(containerPorts);
	// container.setImagePullPolicy("IfNotPresent");
	// List<EnvVar> envVars = new ArrayList<>();
	// envs = new HashMap<>();
	// for (Map.Entry<String, String> entry : envs.entrySet()) {
	// EnvVar envVar = new EnvVar();
	// envVar.setName(entry.getKey());
	// envVar.setValue(entry.getValue());
	// envVars.add(envVar);
	// }
	// container.setEnv(envVars);
	// containers.add(container);
	// podSpec.setContainers(containers);
	// podTemplateSpec.setSpec(podSpec);
	// deploymentSpec.setTemplate(podTemplateSpec);
	//
	// Deployment deployment = new Deployment();
	// deployment.setMetadata(objectMeta);
	// deployment.setSpec(deploymentSpec);
	// return deployment;
	// }

	private ReplicationController constructRc(String rcName, String image, Map<String, String> labels,
			Map<String, String> envs, List<Integer> ports) {
		ObjectMeta objectMeta = new ObjectMeta();
		objectMeta.setName(rcName);
		objectMeta.setNamespace(OpenshiftUtil.DEFAULT_NAMESPACE);

		ReplicationControllerSpec rcSpec = new ReplicationControllerSpec();
		// 默认实例数启动一个
		rcSpec.setReplicas(1);
		PodTemplateSpec podTemplateSpec = new PodTemplateSpec();
		ObjectMeta podObjectMeta = new ObjectMeta();
		podObjectMeta.setLabels(labels);
		podTemplateSpec.setMetadata(podObjectMeta);
		PodSpec podSpec = new PodSpec();
		List<Container> containers = new ArrayList<>();
		Container container = new Container();
		container.setName(rcName);
		container.setImage(image);
		List<ContainerPort> containerPorts = new ArrayList<>();
		for (Integer port : ports) {
			ContainerPort containerPort = new ContainerPort();
			containerPort.setContainerPort(port);
			containerPorts.add(containerPort);
		}
		container.setPorts(containerPorts);
		container.setImagePullPolicy("IfNotPresent");
		List<EnvVar> envVars = new ArrayList<>();
		for (Map.Entry<String, String> entry : envs.entrySet()) {
			EnvVar envVar = new EnvVar();
			envVar.setName(entry.getKey());
			envVar.setValue(entry.getValue());
			envVars.add(envVar);
		}
		container.setEnv(envVars);
		containers.add(container);
		podSpec.setContainers(containers);
		podTemplateSpec.setSpec(podSpec);
		rcSpec.setTemplate(podTemplateSpec);

		ReplicationController rc = new ReplicationController();
		rc.setMetadata(objectMeta);
		rc.setSpec(rcSpec);
		return rc;
	}

	private io.fabric8.kubernetes.api.model.Service constructService(String serviceName, Map<String, String> labels,
			Map<String, String> envs, List<Integer> ports) {
		io.fabric8.kubernetes.api.model.Service service = new io.fabric8.kubernetes.api.model.Service();
		ObjectMeta objectMeta = new ObjectMeta();
		objectMeta.setName(serviceName);
		objectMeta.setNamespace(OpenshiftUtil.DEFAULT_NAMESPACE);
		objectMeta.setLabels(labels);
		service.setMetadata(objectMeta);
		ServiceSpec serviceSpec = new ServiceSpec();
		// 暂时写死，后期可能会改规则
		serviceSpec.setType("NodePort");
		List<ServicePort> servicePorts = new ArrayList<>();
		for (Integer port : ports) {
			ServicePort servicePort = new ServicePort();
			servicePort.setPort(port);
			servicePort.setName(RandomStringUtils.randomAlphanumeric(8).toLowerCase());
			servicePorts.add(servicePort);
		}
		serviceSpec.setPorts(servicePorts);
		serviceSpec.setSelector(labels);
		service.setSpec(serviceSpec);
		return service;
	}

	@Override
	public BsmResult authorize(Long imageId, Long userId, Long deptId) {
		BsmResult bsmResult = new BsmResult();
		try {
			if (softwareDao.authorize(imageId, userId, deptId)) {
				bsmResult.setSuccess(true);
				bsmResult.setMessage("镜像授权成功！");
			} else {
				bsmResult.setMessage("镜像授权失败！");
			}
			return bsmResult;
		} catch (Exception e) {
			logger.error("Authorize image exception: ", e);
			bsmResult.setMessage("镜像授权失败！");
			return bsmResult;
		} finally {
			saveLog("software/operation", "镜像授权", bsmResult.getMessage(), userId);
		}
	}

	/**
	 * 添加镜像中间表
	 * 
	 * @author zjm
	 * @date 2017年4月21日
	 *
	 * @param id
	 * @param bsmResult
	 * @return
	 */
	@Transactional
	private BsmResult insertSoftwareMiddleTable(Long softwareId, Application application, Long clusterId,
			String resourceName) {
		BsmResult bsmResult = new BsmResult();
		bsmResult.setSuccess(false);
		// 判断应用镜像中间表是否包含这个应用和镜像，如果不包含添加应用镜像中间表数据
		ApplicationSoftwareInfo applicationSoftwareInfo = null;
		try {
			applicationSoftwareInfo = applicationSoftwareInfoDao.getByAppIdAndSoftwareId(application.getId(),
					softwareId);
		} catch (Exception e) {
			logger.error("获取应用镜像中间表失败！", e);
			bsmResult.setMessage("获取应用镜像中间表失败！");
			return bsmResult;
		}
		if (null == applicationSoftwareInfo) {
			applicationSoftwareInfo = new ApplicationSoftwareInfo();
			applicationSoftwareInfo.setSoftwareId(softwareId);
			applicationSoftwareInfo.setApplicationId(application.getId());
			applicationSoftwareInfo.setUseCount(1);
			applicationSoftwareInfo.setSoftwareName(getImageByAppIdAndSoftwareId(application.getId(), softwareId));
			if (!saveApplicationSoftwareInfo(applicationSoftwareInfo, bsmResult)) {
				return bsmResult;
			}
		} else {
			applicationSoftwareInfo.setUseCount(applicationSoftwareInfo.getUseCount() + 1);
			try {
				applicationSoftwareInfoDao.updateApplicationSoftwareInfo(applicationSoftwareInfo);
			} catch (Exception e) {
				bsmResult.setSuccess(false);
				bsmResult.setMessage("添加应用镜像关联数据失败！" + e);
				logger.error(bsmResult.getMessage());
				return bsmResult;
			}
		}
		// 添加应用集群中间表数据
		// 判断应用是否在该集群中部署过，防止应用集群信息重复
		ApplicationOpenshiftClusterInfo applicationOpenshiftClusterInfo = null;
		try {
			applicationOpenshiftClusterInfo = applicationOpenshiftClusterInfoDao
					.getApplicationOpenshiftClusterInfo(application.getId());
		} catch (Exception e) {
			logger.error("获取应用集群中间表失败！", e);
			bsmResult.setMessage("获取应用集群中间表失败！");
			return bsmResult;
		}
		if (null == applicationOpenshiftClusterInfo) {
			applicationOpenshiftClusterInfo = new ApplicationOpenshiftClusterInfo();
			applicationOpenshiftClusterInfo.setApplicationId(application.getId());
			applicationOpenshiftClusterInfo.setOpenshiftClusterId(clusterId);
			if (!saveApplicationOpenshiftClusterInfo(applicationOpenshiftClusterInfo, bsmResult)) {
				logger.error(bsmResult.getMessage());
				return bsmResult;
			}
		}
		// 修改应用状态
		application.setStatus(ApplicationEnum.Status.DEPLOY.toString());
		if (!modifyApplication(application, bsmResult)) {
			logger.error(bsmResult.getMessage());
		}
		bsmResult.setSuccess(true);
		return bsmResult;
	}
}
